/*
 * 
 */
package edu.towson.cis.cosc442.project3.vendingmachine;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * The unit test Class for VendingMachine.
 */
public class VendingMachineTest {

	/** Declaring necessary test objects for {@link VendingMachine} */
	VendingMachine machine;

	/**
	 * Initializes the necessary test objects for the test cases to use.
	 *
	 * @throws Exception
	 *             the exception
	 */
	@Before
	public void setUp() throws Exception {

	}

	/**
	 * Test for the addItem() method of the {@link VendingMachine} class
	 */
	@Test
	public void testAddItem() {

		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);
		machine.addItem(new VendingMachineItem("VM Item1", 99.0),
				VendingMachine.B_CODE);
		machine.addItem(new VendingMachineItem("VM Item2", 99.0),
				VendingMachine.C_CODE);
	}

	/**
	 * Test for the getItem() method of the {@link VendingMachine} class. Also
	 * checks that if a splot is empty a null value is returned
	 */
	@Test
	public void testGetItem() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);
		machine.addItem(new VendingMachineItem("VM Item1", 99.0),
				VendingMachine.B_CODE);
		machine.addItem(new VendingMachineItem("VM Item2", 99.0),
				VendingMachine.C_CODE);

		VendingMachineItem item = machine.getItem(VendingMachine.A_CODE);
		assertNotNull(item);
		assertNotNull(item.getName().equals("VM Item0"));
		item = machine.getItem(VendingMachine.B_CODE);
		assertNotNull(item);
		assertNotNull(item.getName().equals("VM Item1"));
		item = machine.getItem(VendingMachine.C_CODE);
		assertNotNull(item);
		assertNotNull(item.getName().equals("VM Item2"));
		item = machine.getItem(VendingMachine.D_CODE);
		assertNull(item);
	}

	/**
	 * Test for the getItem() method of the {@link VendingMachine} class to fail
	 * if the wrong code is passed
	 */
	@Test(expected = VendingMachineException.class)
	public void testGetItemSlotDoesntExists() {
		machine = new VendingMachine();
		assertNotNull(machine);

		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);
		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);
		VendingMachineItem item = machine.getItem(VendingMachine.A_CODE);
		assertNotNull(item);
		item = machine.getItem("wrongcodelol");
	}

	/**
	 * Test for the getItem() method of the {@link VendingMachine} class to fail
	 * if the wrong code is passed
	 */
	@Test(expected = VendingMachineException.class)
	public void testAddItemSlotDoesntExist() {
		machine = new VendingMachine();
		machine.addItem(new VendingMachineItem("VM Item2", 99.0), "wrongcodeyo");
	}

	/**
	 * Test for the addItem() method of the {@link VendingMachine} class to fail
	 * if a new item is added in a slot already occupied.
	 */
	@Test(expected = VendingMachineException.class)
	public void testAddItemAlreadyEmpty() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);

		machine.addItem(new VendingMachineItem("VM Item1", 99.0),
				VendingMachine.A_CODE);
	}

	/**
	 * Test for the removeItem() method of the {@link VendingMachine} class.
	 */
	@Test
	public void testRemoveItem() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);
		machine.addItem(new VendingMachineItem("VM Item1", 99.0),
				VendingMachine.B_CODE);
		machine.addItem(new VendingMachineItem("VM Item2", 99.0),
				VendingMachine.C_CODE);

		machine.removeItem(VendingMachine.A_CODE);
		machine.removeItem(VendingMachine.B_CODE);
	}

	/**
	 * Test for the removeItem() method of the {@link VendingMachine} class to
	 * fail if the item is empty
	 */
	@Test(expected = VendingMachineException.class)
	public void testRemoveItemSlotEmpty() {
		machine = new VendingMachine();

		machine.removeItem(VendingMachine.B_CODE);
	}

	/**
	 * Test for the removeItem() method of the {@link VendingMachine} class to
	 * fail if the wrong code is passed
	 */
	@Test(expected = VendingMachineException.class)
	public void testRemoveItemSplotDoesntExist() {
		machine = new VendingMachine();
		machine.addItem(new VendingMachineItem("VM Item0", 99.0),
				VendingMachine.A_CODE);

		machine.removeItem("anotherwrongcode");
	}

	/**
	 * Test for the insertMoney() method of the {@link VendingMachine} class.
	 */
	@Test
	public void testInsertMoney() {
		machine = new VendingMachine();

		machine.insertMoney(100.0);
	}

	/**
	 * Test for the insertMoney() method of the {@link VendingMachine} class to
	 * fail if the amount inserted is less than zero
	 */
	@Test(expected = VendingMachineException.class)
	public void testInsertMoneyLessthanZero() {
		machine = new VendingMachine();

		machine.insertMoney(-1.0);
	}

	/**
	 * Test for the getBalance() method of the {@link VendingMachine} class.
	 */
	@Test
	public void testGetBalance() {
		machine = new VendingMachine();
		machine.insertMoney(100.0);

		double balance = machine.getBalance();

		assertTrue(new Double(100.0).equals(new Double(balance)));
	}

	/**
	 * Test for the makePurchase() method of the {@link VendingMachine} class.
	 */
	@Test
	public void testMakePurchase() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("Item0", 99.0),
				VendingMachine.A_CODE);
		machine.insertMoney(100.0);

		assertTrue(machine.makePurchase(VendingMachine.A_CODE));
	}
	
	/**
	 * Test for the makePurchase() method of the {@link VendingMachine} class.
	 */
	@Test
	public void testMakePurchaseWithNullItem() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("Item0", 99.0),
				VendingMachine.A_CODE);
		machine.insertMoney(100.0);

		assertFalse(machine.makePurchase(VendingMachine.B_CODE));
	}

	/**
	 * Test for the makePurchase() method of the {@link VendingMachine} class.
	 */
	@Test
	public void testMakePurchaseWithInsufficentFunds() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("Item0", 99.0),
				VendingMachine.A_CODE);
		machine.insertMoney(98.0);

		assertFalse(machine.makePurchase(VendingMachine.A_CODE));
	}

	/**
	 * Test for the returnChange() method of the {@link VendingMachine} class.
	 */
	@Test
	public void restReturnChange() {
		machine = new VendingMachine();

		machine.addItem(new VendingMachineItem("Item0", 99.0),
				VendingMachine.A_CODE);
		machine.insertMoney(100.0);

		machine.makePurchase(VendingMachine.A_CODE);
		assertTrue(new Double(machine.returnChange()).equals(new Double(1.0)));
	}

	/**
	 * Cleans up test objects after a test case is executed.
	 */
	@After
	public void tearDown() {
		machine = null;
	}
}
